package edu.elon.cs.mobile.ukulele;

/**
 *  Main screen for the Ukulele app.
 * 
 *  @author C. Dierk and J. Hollingsworths
 */

import java.util.ArrayList;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
import android.widget.Toast;
import android.widget.ToggleButton;

public class SurfaceViewer extends SurfaceView implements SurfaceHolder.Callback{

	private SurfaceHolder surfaceHolder;
	private Bitmap ukulele;
	private float x1, y1;
	private Dot[] dots;
	private Chord[] chords;
	private Canvas canvas;
	private Paint dotpaint;
	private ArrayList<Dot> chosenDots;
	private GestureDetector gd;
	private ArrayList<Chord> progression;
	private ToggleButton tb;
	private Button button;
	private LinearLayout progressionArea;
	private HorizontalScrollView scrollView;
	private ProgressionPlay pp; 

	public SurfaceViewer(Context context, AttributeSet attrs) {
		super(context, attrs);

		// drawing canvas
		surfaceHolder = getHolder();
		surfaceHolder.addCallback(this);
		ukulele = BitmapFactory.decodeResource(context.getResources(), R.drawable.ukulele);
		
		// strum detection
		gd = new GestureDetector(context, gestureListener);

		// possible finger points
		dots = new Dot[6];
		dots[0] = new Dot("s1f3",210f,213f);
		dots[1] = new Dot("s2f3",210f,240f);
		dots[2] = new Dot("s1f2",145f,213f);
		dots[3] = new Dot("s3f2",145f,267f);
		dots[4] = new Dot("s4f2",145f,293f);
		dots[5] = new Dot("s2f1",80f,240f);
		dotpaint = new Paint();
		dotpaint.setColor(Color.MAGENTA);
		chosenDots = new ArrayList<Dot>();
				
		// possible chords
		chords = new Chord[4];
		chords[0] = new Chord("C", getContext(), R.raw.cstrum, R.raw.cchord, R.drawable.c, dots[0]);
		chords[1] = new Chord("G", getContext(), R.raw.gstrum, R.raw.gchord, R.drawable.g, dots[1], dots[2], dots[3]);
		chords[2] = new Chord("Am", getContext(), R.raw.amstrum, R.raw.amchord, R.drawable.am, dots[4]);
		chords[3] = new Chord("F", getContext(), R.raw.fstrum, R.raw.fchord, R.drawable.f, dots[4], dots[5]);
		
		// the chord progression -- empty for now
		progression = new ArrayList<Chord>();
		pp = null;
	}
	

	/**
	 *  Listener for the Play/Stop button.
	 */
	private OnClickListener playListener = new OnClickListener(){

		public void onClick(View v) {

			if (button.getText().equals("Stop")) {
				// nicely shutdown the progression play thread
				if (pp != null) {
					pp.setRunning(false);
					boolean retry = true;
					while (retry) {
						try {
							pp.join();
							retry = false;
						}
						catch (InterruptedException ex) { }
					}
				}
				
				// change the text of the button
				button.setText("Play");

			} else {				
				// kick off a thread to play the progression
				pp = new ProgressionPlay();
				pp.setRunning(true);
				pp.start();
				
				// change the text of the button
				button.setText("Stop");
			}
		}
	};


	/**
	 *  Listener for the strum gesture.
	 */
	private GestureDetector.OnGestureListener gestureListener = new GestureDetector.OnGestureListener() {

		@Override
		public boolean onDown(MotionEvent event) {
			x1 = event.getX();
			y1 = event.getY();
			processTouch(x1,y1);
			try {
				canvas = surfaceHolder.lockCanvas();
				canvas.drawBitmap(ukulele, 0, 0, null);
				for (int i = 0; i < chosenDots.size(); i++){
					canvas.drawCircle(chosenDots.get(i).getX(), chosenDots.get(i).getY(), 15f, dotpaint);
				}
			} finally {
				if (canvas != null) {
					surfaceHolder.unlockCanvasAndPost(canvas);
				}

			}
			return true;
		}

		@Override
		public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
				float velocityY) {
			return false;
		}

		@Override
		public void onLongPress(MotionEvent e) {
		}

		@Override
		public boolean onScroll(MotionEvent e1, MotionEvent e2,
				float distanceX, float distanceY) {
			if (e1.getX() > 735 && e1.getX() < 1120 && e1.getY() < 215 && e2.getY() > 325){
				processChord();
			}
			return false;
		}

		@Override
		public void onShowPress(MotionEvent e) {
		}

		@Override
		public boolean onSingleTapUp(MotionEvent e) {
			return false;
		}


	};

	/**
	 *  Let the activity tell us about user interface. 
	 */
	public void setToggleButton(ToggleButton tb){
		this.tb = tb;
	}
	
	public void setbutton(Button button) {
		this.button = button;
		button.setOnClickListener(playListener);
	}

	public void setProgressionArea(HorizontalScrollView hsv, LinearLayout ll) {
		scrollView = hsv;
		progressionArea = ll;
	}
	
	/*
	 *  Process touch events.
	 */
	@Override
	public boolean onTouchEvent(MotionEvent me) {
		// pass through touches to the gesture detector
		return gd.onTouchEvent(me);
	}

	/**
	 * ???
	 */
	private void processChord() {
		Chord chosen = determineMatch();
		if (chosen != null){
			Chord temporary = new Chord(chosen);
			progression.add(temporary);
			updateProgressionArea(temporary);
		}
		chosenDots = new ArrayList<Dot>();
		try {
			canvas = surfaceHolder.lockCanvas();
			canvas.drawBitmap(ukulele, 0, 0, null);
		} finally {
			if (canvas != null) {
				surfaceHolder.unlockCanvasAndPost(canvas);
			}
		}
	}
	
	/**
	 * ???
	 */
	private Chord determineMatch() {
		for (int i = 0; i < chords.length; i++){
			chosenDots.trimToSize();
			if(chords[i].getDots().length == chosenDots.size()){
				boolean match = true;
				ArrayList<Dot> temporary = new ArrayList<Dot>();
				for (int j = 0; j < chords[i].getDots().length; j++){
					temporary.addAll(chosenDots);
					boolean exists = temporary.remove(chords[i].getDots()[j]);
					if (!exists){
						match = false;
					}
				}
				if (match){
					Toast.makeText(getContext(), chords[i].getName(), Toast.LENGTH_SHORT).show();

					if(!tb.isChecked()){
						chords[i].playChord();
					}else{
						chords[i].playStrum();
					}
					return chords[i];
				}
			}
		}
		return null;
	}

	/**
	 * ???
	 */
	private void processTouch(float x, float y) {
		for (int i = 0; i < dots.length; i++){
			if(x > dots[i].getLowerX() && x < dots[i].getUpperX()){
				if(y > dots[i].getLowerY() && y < dots[i].getUpperY()){
					if (!chosenDots.contains(dots[i])){
						for(int j = 0; j < chosenDots.size(); j++){
							if(chosenDots.get(j).getY() == dots[i].getY()){
								chosenDots.remove(j);
							}
						}
						chosenDots.add(dots[i]);
					}else{
						chosenDots.remove(dots[i]);
					}
					return;
				}
			}
		}
	}

	/**
	 *  Long click listener for removing chords from the progression.
	 */
	private OnLongClickListener chordOnLongClickListener = new OnLongClickListener() {

		@Override
		public boolean onLongClick(View view) {
			progressionArea.removeView(view);
			progression.remove(view);
			return true;
		}

	};

	/**
	 *  Show given chord on the screen.
	 */
	private void updateProgressionArea(Chord chord) {

		// look-and-feel
		chord.setAdjustViewBounds(true);
		chord.setPadding(4, 0, 4, 0);
		
		// allow the chord to be deleted
		chord.setOnLongClickListener(chordOnLongClickListener);
		
		// add to the screen
		progressionArea.addView(chord);

		// scroll when a new item is off the screen
		postDelayed(new Runnable() {
			public void run() {
				scrollView.fullScroll(HorizontalScrollView.FOCUS_RIGHT);
			}
		}, 100L);
	}
	
	
	/**
	 *  SurfaceHolder methods
	 */
	@Override
	public void surfaceCreated(SurfaceHolder holder) {

		canvas = null;

		try {
			canvas = surfaceHolder.lockCanvas();
			canvas.drawBitmap(ukulele, 0, 0, null);
		} finally {
			if (canvas != null) {
				surfaceHolder.unlockCanvasAndPost(canvas);
			}
		}
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) { }
	
	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { }
	

	/**
	 * Thread that plays the current chord progression.
	 * 
	 * @author C. Dierk and J. Hollingsworth
	 */
	private class ProgressionPlay extends Thread {
		
		private final int DELAY = 1950;
		private boolean isRunning;
		
		public ProgressionPlay() {
			isRunning = false;
		}
		
		public void setRunning(boolean b) {
			isRunning = b;
		}
		
		public void run() {
			while(isRunning){
				// loop through the progression
				for(int i = 0; i < progression.size() && isRunning; i++){
					if(!tb.isChecked()){
						progression.get(i).playChord();
					}else{
						progression.get(i).playStrum();
					}
					
					// pause for DELAY amount of time
					try {
						Thread.sleep(DELAY);
					} catch (InterruptedException e) { }
				}
			}	
		}
	}
	
}
